package com.test.dao.hibernate;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.test.clyq.entity.Users;
import com.test.clyq.entity.UsersLog;
import com.test.dao.Dao;
import com.test.entity.Item;
import com.test.util.FormatExceptionStack;
import com.test.util.ItemUtil;
import com.test.util.Pagination;

/**
 * This class serves as the Base class for all other Daos - namely to hold
 * common methods that they might all use. Can be used for standard CRUD
 * operations.
 * </p>
 * <p>
 * <a href="BaseDaoHibernate.java.html"><i>View Source</i></a>
 * </p>
 * 
 * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
 */
public class BaseDaoHibernate extends HibernateDaoSupport implements Dao {

	private final static boolean USERLOG_FLAG = true;

	protected final Log log = LogFactory.getLog(getClass());

	/**
	 * @see com.eport.ghostforest.dao.Dao#getObject(java.lang.Class,
	 *      java.io.Serializable)
	 */
	public Item getItem(Class<? extends Item> clazz, Serializable id) {
		Item o = (Item) getHibernateTemplate().get(clazz, id);

		if (o == null) {
			throw new ObjectRetrievalFailureException(clazz, id);
		}

		return o;
	}

	/**
	 * @see com.eport.ghostforest.dao.Dao#getItems(java.lang.Class)
	 */
	@SuppressWarnings("unchecked")
	public List<Item> getItems(Class<? extends Item> clazz) {
		return getHibernateTemplate().loadAll(clazz);
	}

	public Object getObject(Class clazz, Serializable id) {
		// TODO Auto-generated method stub
		return null;
	}

	public List getObjects(Class clazz) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 功能：非分页查询
	 * 
	 * @param hql
	 *            查询hql语句
	 * @param para
	 *            参数
	 * @return
	 * @throws Exception
	 */
	public List listWithoutPagination(final String hql, final List para) throws Exception {

		this.log.debug("[BaseDaoHibernate][listWithoutPagination()][hql]:[" + hql + "]");
		List result = new ArrayList();

		try {
			result = getHibernateTemplate().find(hql, para.toArray());
		}
		catch (Exception e) {
			this.log.error("[BaseDaoHibernate][listWithoutPagination()][Hibernate ExecuteFind][ERROR].");
			FormatExceptionStack.formatException(e);
			if (this.log.isDebugEnabled()) {
				e.printStackTrace();
			}
		}

		if (result != null && result.size() > 0) {
			return result;
		} else {
			return null;
		}
	}

	/**
	 * 功能：分页查询
	 * 
	 * @param totalhql
	 *            获取查询总数的hql语句
	 * @param hql
	 *            查询hql语句
	 * @param para
	 *            参数
	 * @param pagination
	 *            分页对象
	 * @return
	 * @throws Exception
	 */
	public List listWithPagination(final String totalhql, final String hql, final List para, final Pagination pagination) throws Exception {
		try {
			this.log.debug("[BaseDaoHibernate][listWithPagination()][totalhql]:[" + totalhql + "]");
			this.log.debug("[BaseDaoHibernate][listWithPagination()][hql]:[" + hql + "]");
			for (int i = 0; para != null && i < para.size(); i++) {
				this.log.debug("[BaseDaoHibernate][listWithPagination()]para[" + i + "]:[" + para.get(i) + "]");
			}
			this.log.debug("[BaseDaoHibernate][listWithPagination()][pagination.getCurrentPage()]:[" + pagination.getCurrentPage() + "]");
			this.log.debug("[BaseDaoHibernate][listWithPagination()][pagination.getTotalRows()]:[" + pagination.getTotalRows() + "]");

			List list = getHibernateTemplate().find(totalhql.toString(), para.toArray());
			if (!list.isEmpty()) {
				pagination.setTotalRows(((Integer) list.get(0)).intValue());
			} else {
				return null;
			}
			this.log.debug("[BaseDaoHibernate][listWithPagination()][pagination.getTotalRows()]:[" + pagination.getTotalRows() + "]");

			return getHibernateTemplate().executeFind(new HibernateCallback() {

				public Object doInHibernate(Session session) throws HibernateException, SQLException {

					Query query = session.createQuery(hql.toString());
					for (int i = 0; para != null && i < para.size(); i++) {
						query.setParameter(i, para.get(i));
					}
					query.setFirstResult(pagination.getNumPerPage() * (pagination.getCurrentPage() - 1));
					query.setMaxResults(pagination.getNumPerPage());

					List result = query.list();
					if (result != null && result.size() > 0) {
						return result;
					} else {
						return null;
					}
				}
			});
		}
		catch (Exception e) {
			this.log.error("[BaseDaoHibernate][listWithPagination()][Hibernate ExecuteFind][ERROR]." + FormatExceptionStack.formatException(e));
			if (this.log.isDebugEnabled()) {
				e.printStackTrace();
			}
			return null;
		}
	}

	/**
	 * @see com.eport.ghostforest.dao.Dao#removeItem(java.lang.Class,
	 *      java.io.Serializable)
	 */
	public boolean removeItem(Class<? extends Item> clazz, Serializable id, Users user) {
		Item item = getItem(clazz, id);
		if (BaseDaoHibernate.USERLOG_FLAG && user == null) {
			getHibernateTemplate().delete(item);
			return true;
		}

		return removeItem(item, user);
	}

	public boolean removeItem(Item item, Users user) {
		if (item == null) {
			return false;
		}
		if (BaseDaoHibernate.USERLOG_FLAG && user == null) {
			return false;
		}

		long starttime = System.currentTimeMillis();
		String beforeData = null;
		long itemId = -1;
		boolean flag = false;
		try {
			if (BaseDaoHibernate.USERLOG_FLAG && ItemUtil.isLog(item.getClass())) {
				beforeData = item.toXML();
				itemId = item.getId();
			}
			getHibernateTemplate().delete(item);
			flag = true;
		}
		catch (HibernateException e) {
			this.log.error("BaseDaoHibernate::removeItem(): " + e.getMessage());
			e.printStackTrace();
		}
		if (BaseDaoHibernate.USERLOG_FLAG && ItemUtil.isLog(item.getClass())) {
			saveUsesLog((System.currentTimeMillis() - starttime), ItemUtil.DELETEWORKTYPE, ItemUtil.getOperateDataType(item.getClass()), (flag ? 1
			        : 0), beforeData, null, itemId, user);
		}
		return flag;
	}

	public void removeObject(Class clazz, Serializable id) {
		// TODO Auto-generated method stub

	}

	public void saveObject(Object o) {
		getHibernateTemplate().save(o);

	}

	/**
	 * @see com.eport.ghostforest.dao.Dao#saveObject(java.lang.Object)
	 */
	public boolean saveOrUpdateItem(Item item, Users user) {
		if (item == null) {
			return false;
		}
		if (item != null && user == null) {
			getHibernateTemplate().saveOrUpdate(item);
			return true;
		}
		long starttime = System.currentTimeMillis();
		long operateType = -1;
		String beforeData = null;
		String afterData = null;
		boolean flag = false;
		try {
			if (BaseDaoHibernate.USERLOG_FLAG && ItemUtil.isLog(item.getClass())) {
				operateType = ItemUtil.getOperateType(item);
				if (item.getId() != null) {
					Item oldItem = getItem(item.getClass(), item.getId());
					beforeData = oldItem.toXML();
					try {
						BeanUtils.copyProperties(oldItem, item);
					}
					catch (IllegalAccessException e) {
						e.printStackTrace();
					}
					catch (InvocationTargetException e) {
						e.printStackTrace();
					}

					getHibernateTemplate().saveOrUpdate(oldItem);

				} else {
					getHibernateTemplate().saveOrUpdate(item);
				}

			} else {
				getHibernateTemplate().saveOrUpdate(item);
			}
			if (BaseDaoHibernate.USERLOG_FLAG && ItemUtil.isLog(item.getClass())) {
				afterData = item.toXML();
			}

			flag = true;
		}
		catch (HibernateException e) {
			this.log.error("BaseDaoHibernate::saveOrUpdateItem( item , user ): " + e.getMessage());
			e.printStackTrace();
		}

		if (BaseDaoHibernate.USERLOG_FLAG && ItemUtil.isLog(item.getClass())) {
			saveUsesLog((System.currentTimeMillis() - starttime), operateType, ItemUtil.getOperateDataType(item.getClass()), (flag ? 1 : 0),
			            beforeData, afterData, item.getId(), user);
		}
		return flag;
	}

	public boolean saveOrUpdateItems(Collection<Item> items, Users user) {
		if (items == null) {
			return false;
		}
		if (BaseDaoHibernate.USERLOG_FLAG && user == null) {
			return false;
		}
		try {
			if (!items.isEmpty()) {
				Iterator<Item> iterator = items.iterator();
				while (iterator.hasNext()) {
					Item item = iterator.next();
					if (item != null) {
						getHibernateTemplate().saveOrUpdate(item);
					}
				}
			}
		}
		catch (HibernateException e) {
			this.log.error("BaseDaoHibernate::saveOrUpdateItems( Collection , user ): " + e.getMessage());
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public boolean saveOrUpdateBatchItems(List<Item> items, Users user) {
		if (items == null) {
			return false;
		}
		SessionFactory sessionFactory = getHibernateTemplate().getSessionFactory();
		Session session = sessionFactory.openSession();
		try {

			Transaction tx = session.beginTransaction();
			if (!items.isEmpty()) {
				Iterator<Item> iterator = items.iterator();
				int flag = 1;
				while (iterator.hasNext()) {
					Item item = iterator.next();
					if (item != null) {
						session.save(item);
						if (flag % 25 == 0) { // 单次批量操作的数目为20
							session.flush(); // 清理缓存，执行批量插入20条记录的SQL insert语句
							session.clear(); // 清空缓存中的Customer对象
						}
						flag++;
					}
				}
				session.flush(); // 清理缓存，执行批量插入20条记录的SQL insert语句
				session.clear(); // 清空缓存中的Customer对象
				tx.commit();

			}
		}
		catch (HibernateException e) {
			this.log.error("BaseDaoHibernate::saveOrUpdateBatchItems( Collection , user ): " + e.getMessage());
			e.printStackTrace();
			return false;
		}
		finally {
			session.close();
		}
		return true;
	}

	public boolean saveOrUpdateItems(Item[] items, Users user) {
		if (items == null) {
			return false;
		}
		if (BaseDaoHibernate.USERLOG_FLAG && user == null) {
			return false;
		}
		int size = items.length;
		try {
			for (int i = 0; i < size; i++) {
				if (items[i] != null) {
					getHibernateTemplate().saveOrUpdate(items[i]);
				}
			}
		}
		catch (HibernateException e) {
			this.log.error("BaseDaoHibernate::saveOrUpdateItems(item[] , user ): " + e.getMessage());
			e.printStackTrace();
			return false;
		}
		return false;
	}

	/** 保存工作日志 */
	private void saveUsesLog(long usedTime, long operateType, long operateDataType, long operateStatus, String beforeOperateData,
	        String afterOperateData, Long operateTableKey, Users users) {

		UsersLog userLog = new UsersLog();

		userLog.setOperateTime(System.currentTimeMillis());
		userLog.setUsedTime(usedTime);

		userLog.setUsersId(users.getId());
		userLog.setUsersLoginName(users.getUsersLoginName());
		// userLog.setLoginWebsiteId(users.getCurrentWebsiteId());

		userLog.setOperateType(operateType);
		userLog.setOperateDataType(operateDataType);
		userLog.setOperateStatus(operateStatus);
		userLog.setOperateTableKey(operateTableKey);

		userLog.setBeforeOperateData(beforeOperateData);
		userLog.setAfterOperateData(afterOperateData);

		getHibernateTemplate().saveOrUpdate(userLog);

	}
}
